#ifndef _SHARP_KEYLIST_H
#define _SHARP_KEYLIST_H

#include "sharp-common.h"

/**
 * @file src/keylist.c
 */

typedef struct sharp_keylist_s sharp_keylist;

/**
 * Keeps information about the sharp_keylist.
 * The keylist is singly linked.
 */
struct sharp_keylist_s {
    /** The key. Must be a string, strcasecmp() is performed on it. */
    char *key;
    /** Pointer to data. */
    void *data;
    /** Pointer to the next entry. */
    sharp_keylist *next;
};

/**
 * initialize a keylist
 * @param list pointer to list to be initialized
 *
 * Should be used when first created as a local variable.  The list will
 * actually just be set to be NULL, and space for it will be allocated at a
 * later point, meaning that lists that are just initialized take no space.
 * Currently always returns true.
 */
bool sharp_keylist_init(sharp_keylist **list);

/**
 * create a new node and add it to the keylist
 * @param list pointer to pointer to a sharp keylist
 * @param key name of key that determines the position of the presorted node
 *  The contents of key is not copied. It would be wise to point to
 *  somewhere in the data structure. Key is not case sensitive.
 * @param data generalized pointer to a structure which contains the information
 *  for this node.
 *
 * If a node at key already exists, it will be overwritten.  Returns true on
 * success, false if there were issues in inserting the data; this usually
 * only happens when malloc fails.
 */
bool sharp_keylist_insert(sharp_keylist **list, char *key, void *data);

/**
 * remove the node whose key matches the given key
 * @param list pointer to a sharp keylist
 * @param key name of key of target node
 * @param data pointer where the resulting data will be returned upon deletion
 *  of node
 *
 * The key is not case-sensitive.
 */
bool sharp_keylist_remove(sharp_keylist **list, char *key, void **data);

/**
 * move data from key to a new key name
 * @param list pointer to a sharp keylist
 * @param key name of key of target node
 * @param new_key name of new key to be moved to.
 *
 * The node named key will no longer exist.  The node at newkey will be
 * overwritten if it already exists.  The key of the to-be-moved node is
 * not case-sensitive.
 */
bool sharp_keylist_move(sharp_keylist **list, char *key, char *new_key);

/**
 * return the pointer to data in the node named key
 * @param list pointer to a sharp keylist
 * @param key name of key of target node
 * @param data output pointer to data that will be retrieved.
 * 
 * The key name is not case-sensitive.  Returns false if the key wasn't found.
 */
bool sharp_keylist_get(sharp_keylist *list, char *key, void **data);

/**
 * get a node, using a function to match
 * @param list pointer to a sharp keylist
 * @param key output pointer to key of matched node.
 * @param data output pointer to data that will be retrieved.
 * @param matches_data a function that returns true if the data matches it.
 * @param withdata pointer to extra data passed into matches_data.
 */
bool sharp_keylist_get_manual(sharp_keylist *list, char **key, void **data,
    bool (*matches_data)(void *data, void *withdata), void *withdata);

/**
 * Iterates to the next node of the keylist.
 * @param list pointer to a sharp keylist
 * @param next pointer to current node of list. This node gets changed to the next
 *  node of the list when called.
 *  If NULL, returns the list.
 *
 * Returns false if on the last node.
 */
bool sharp_keylist_iter(sharp_keylist *list, sharp_keylist **next);

/**
 * Returns true if list is empty, false otherwise.
 * @param list pointer to a sharp keylist
 */
bool sharp_keylist_isempty(sharp_keylist *list);

#endif /* _SHARP_KEYLIST_H */
